<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>TPBlocks</title>
<style>
  body { font-family: system-ui, -apple-system, "Segoe UI", Arial; display:flex; flex-direction:column; align-items:center; gap:16px; padding:20px; background:#f7f7f7; margin:0; }
  h1 { margin:0; font-size:20px; }
  .mode-indicator { font-size:16px; font-weight:600; color:#666; }
  .board { display:grid; grid-template-columns: repeat(5, 64px); grid-template-rows: repeat(5, 64px); gap:6px; }
  .cell { width:64px; height:64px; border-radius:10px; display:flex; align-items:center; justify-content:center; font-weight:700; font-size:18px; cursor:pointer; background:#e6e6e6; color:#fff; box-shadow: inset 0 0 0 2px #ddd; transition: transform 0.1s; }
  .cell:hover { transform: scale(1.05); }
  .cell.empty { color:#999; background:#f0f0f0; box-shadow: inset 0 0 0 2px #e4e4e4; }
  .cell.selected { outline: 3px solid #ff9f1c; }
  .block-1 { background:#ff6b6b; }
  .block-2 { background:#4ecdc4; }
  .block-3 { background:#ffd166; color:#333; }
  .block-4 { background:#06d6a0; }
  .block-5 { background:#118ab2; }
  .block-6 { background:#8338ec; }
  .block-7 { background:#fb5607; }
  .block-8 { background:#3a86ff; }
  .block-9 { background:#e63946; }
  .block-10 { background:#2a9d8f; }
  .block-11 { background:#f77f00; }
  .block-12 { background:#d62828; }
  .panel { display:flex; gap:8px; flex-wrap:wrap; justify-content:center; max-width:700px; }
  button { padding:10px 16px; border:0; border-radius:8px; background:#999; color:#fff; font-weight:600; cursor:pointer; transition: background 0.2s; font-size:14px; }
  button:hover { background:#777; }
  button:active { background:#2b7 !important; }
  button.secondary { background:#999; }
  button.secondary:hover { background:#777; }
  button.secondary:active { background:#2b7 !important; }
  button.danger { background:#e74; }
  button.danger:hover { background:#c52; }
  button.danger:active { background:#2b7 !important; }
  button.active { background:#2b7 !important; }
  button.active:hover { background:#1a6 !important; }
  button.active:active { background:#2b7 !important; }
  .msg { min-height:28px; color:#333; font-weight:500; font-size:15px; text-align:center; }
  .score { font-size:18px; font-weight:700; color:#2b7; margin:8px 0; }
  
  /* 编辑器预览 */
  #nextBlockPreview { box-shadow: 0 2px 6px rgba(0,0,0,0.15); }
  
  /* 关卡列表 */
  .level-list { max-width:500px; background:#fff; border-radius:10px; padding:16px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); max-height:400px; overflow-y:auto; }
  .level-item { padding:12px; background:#f7f7f7; border-radius:8px; margin-bottom:8px; cursor:pointer; transition:all 0.2s; display:flex; justify-content:space-between; align-items:center; }
  .level-item:hover { background:#e0e0e0; transform: translateX(4px); }
  .level-item button { padding:6px 12px; font-size:12px; margin-left:8px; }
  
  .info { max-width:680px; font-size:13px; line-height:1.5; color:#666; background:#fff; padding:10px 14px; border-radius:8px; box-shadow: 0 2px 6px rgba(0,0,0,0.05); margin-top:8px; }
  
  .view { display:none; }
  .view.active { display:flex; flex-direction:column; align-items:center; gap:16px; }
  
  .save-input { padding:10px; border-radius:6px; border:2px solid #ddd; width:250px; font-size:14px; margin-right:8px; }
</style>
</head>
<body>
  <h1>TPBlocks</h1>
  <div class="mode-indicator" id="modeIndicator">🎮 游戏模式</div>

  <div class="panel">
    <button id="playModeBtn" class="active">游戏模式</button>
    <button id="endlessModeBtn" class="secondary">无尽模式</button>
    <button id="editorModeBtn" class="secondary">关卡编辑器</button>
    <button id="loadLevelBtn" class="secondary">载入关卡</button>
  </div>

  <!-- 游戏模式视图 -->
  <div id="playView" class="view active">
    <div class="panel">
      <button id="resetBtn">随机关卡</button>
      <button id="presetBtn" class="secondary">示例关卡</button>
    </div>
    <div id="playBoard" class="board"></div>
    <div id="playMsg" class="msg"></div>
    <div class="info">
      <b>玩法：</b>点击方块选中，用方向键移动。方块可传送，相同数字方块相邻滑动会消除。A game designed by sdsds222 (2025)
    </div>
  </div>

  <!-- 无尽模式视图 -->
  <div id="endlessView" class="view">
    <div class="panel">
      <button id="endlessStartBtn">开始游戏</button>
      <button id="endlessRestartBtn" class="secondary" style="display:none;">重新开始</button>
    </div>
    <div class="score" id="endlessScore">移动次数: 0</div>
    <div id="endlessBoard" class="board"></div>
    <div id="endlessMsg" class="msg"></div>
    <div class="info">
      <b>无尽模式：</b>每3次成功移动（包括消除、传送、对调）都会添加一对新方块。数字优先递增（1→2→3...），当超过12后会重用已消除的1-12号颜色以保持视觉对比度。当没有空位添加新方块时游戏结束！
    </div>
  </div>

  <!-- 编辑器视图 -->
  <div id="editorView" class="view">
    <div class="panel">
      <button id="placeBtn">放置方块</button>
      <button id="deleteBtn">删除方块</button>
      <button id="clearBtn" class="danger">清空棋盘</button>
    </div>
    <div style="margin: 8px 0; font-size: 14px; color: #666;">
      <span>下一个方块：</span>
      <span id="nextBlockPreview" style="display:inline-block; width:32px; height:32px; border-radius:6px; text-align:center; line-height:32px; color:#fff; font-weight:700; margin-left:8px;"></span>
      <span id="nextBlockText" style="margin-left:8px; font-weight:600;"></span>
      <span id="capacityInfo" style="margin-left:16px; font-weight:600; color:#666;"></span>
    </div>
    <div class="panel">
      <button id="testBtn">▶ 测试关卡</button>
      <button id="saveBtn">保存关卡</button>
      <button id="backToEditBtn" class="secondary" style="display:none;">返回编辑</button>
    </div>
    <div id="editorBoard" class="board"></div>
    <div id="editorMsg" class="msg"></div>
    <div id="saveArea" style="display:none; margin-top:8px;">
      <input type="text" id="levelName" class="save-input" placeholder="输入关卡名称...">
      <button onclick="saveLevelWithName()">确认</button>
      <button onclick="cancelSave()" class="secondary">取消</button>
    </div>
    <div class="info">
      <b>编辑器：</b>点击"放置方块"，然后点击棋盘两次放置一对配对方块。自动按顺序编号。棋盘最多放置12对方块（需保留至少1个空格）。
    </div>
  </div>

  <!-- 载入关卡视图 -->
  <div id="loadView" class="view">
    <div class="level-list" id="levelList"></div>
    <div class="info">
      <b>提示：</b>点击关卡即可载入到游戏模式。在编辑器中保存的关卡会显示在这里。
    </div>
  </div>

<script>
  const SIZE = 5;
  const DIRS = {
    ArrowUp: {x:0, y:-1}, ArrowDown: {x:0, y:1},
    ArrowLeft: {x:-1, y:0}, ArrowRight: {x:1, y:0}
  };

  let currentView = 'play';
  let currentMode = 'play'; // play, endless, editor, editorTest
  let board = Array.from({length:SIZE}, ()=> Array(SIZE).fill(0));
  let selected = null;
  let blocksRemaining = 0;
  
  // 编辑器状态
  let editorMode = 'place'; // 'place' or 'delete'
  let nextBlockNumber = 1;
  let placingBlock = null; // {type: number, firstPos: {x, y}} 正在放置的方块
  
  // 无尽模式状态
  let endlessMoves = 0;
  let endlessNextType = 1; // 下一个要添加的方块类型
  let endlessGameOver = false;
  let movesUntilNewBlocks = 0; // 添加新方块前的剩余移动次数

  function inside(x,y){ return x>=0 && x<SIZE && y>=0 && y<SIZE; }

  // ========== 视图切换 ==========
  function switchView(view, preserveBoard = false){
    document.querySelectorAll('.view').forEach(v => v.classList.remove('active'));
    document.getElementById(view + 'View').classList.add('active');
    currentView = view;
    
    // 更新顶部按钮状态
    const allBtns = document.querySelectorAll('#playModeBtn, #endlessModeBtn, #editorModeBtn, #loadLevelBtn');
    allBtns.forEach(btn => {
      btn.classList.remove('active');
      btn.classList.add('secondary');
    });
    
    const btnMap = {
      play: 'playModeBtn',
      endless: 'endlessModeBtn',
      editor: 'editorModeBtn',
      load: 'loadLevelBtn'
    };
    const activeBtn = document.getElementById(btnMap[view]);
    activeBtn.classList.remove('secondary');
    activeBtn.classList.add('active');
    
    const indicators = {
      play: '游戏模式',
      endless: '无尽模式',
      editor: '关卡编辑器',
      load: '载入关卡'
    };
    document.getElementById('modeIndicator').textContent = indicators[view];
    
    // 修复：切换视图时更新当前模式
    if (view === 'play') {
      currentMode = 'play';
      if(!preserveBoard){
        resetRandom();
      } else {
        renderBoard('play');
      }
    } else if (view === 'endless') {
      currentMode = 'endless';
    } else if (view === 'editor') {
      currentMode = 'editor';
      initEditor();
    }
  }

  document.getElementById('playModeBtn').onclick = () => {
    switchView('play');
  };
  
  document.getElementById('endlessModeBtn').onclick = () => {
    switchView('endless');
    showMsg('endless', '点击"开始游戏"开始无尽挑战！');
  };
  
  document.getElementById('editorModeBtn').onclick = () => {
    switchView('editor');
  };
  
  document.getElementById('loadLevelBtn').onclick = () => {
    switchView('load');
    loadSavedLevels();
  };

  // ========== 游戏模式 ==========
  function resetRandom(){
    board = Array.from({length:SIZE}, ()=> Array(SIZE).fill(0));
    const pairs = [1,2,3,4,5];
    pairs.forEach(t => placeRandomPair(t));
    selected = null;
    renderBoard('play');
    showMsg('play', '随机关卡已生成');
  }

  function loadPreset(){
    board = Array.from({length:SIZE}, ()=> Array(SIZE).fill(0));
    board[0][2]=1; board[0][3]=1;
    board[0][0]=2; board[0][1]=2;
    board[2][2]=3; board[2][4]=3;
    board[1][1]=4; board[3][3]=4;
    board[4][4]=5; board[0][4]=5;
    selected = null;
    renderBoard('play');
    showMsg('play', '示例关卡已载入');
  }

  function placeRandomPair(type){
    let placed = 0;
    while(placed < 2){
      const x = Math.floor(Math.random()*SIZE);
      const y = Math.floor(Math.random()*SIZE);
      if(board[y][x] === 0){
        board[y][x] = type;
        placed++;
      }
    }
  }

  document.getElementById('resetBtn').onclick = resetRandom;
  document.getElementById('presetBtn').onclick = loadPreset;

  // ========== 无尽模式 ==========
  function startEndless(){
    board = Array.from({length:SIZE}, ()=> Array(SIZE).fill(0));
    // 初始放置3对方块
    placeRandomPair(1);
    placeRandomPair(2);
    placeRandomPair(3);
    endlessMoves = 0;
    movesUntilNewBlocks = 3; // 初始设置为3，需要3次移动才添加新方块
    endlessNextType = 4; // 下一个要添加的类型从4开始
    endlessGameOver = false;
    selected = null;
    currentMode = 'endless';
    document.getElementById('endlessStartBtn').style.display = 'none';
    document.getElementById('endlessRestartBtn').style.display = 'inline-block';
    updateEndlessScore();
    renderBoard('endless');
    showMsg('endless', '无尽模式开始！每3次成功移动添加一对新方块');
  }

  function updateEndlessScore(){
    document.getElementById('endlessScore').textContent = `移动次数: ${endlessMoves} (还需${movesUntilNewBlocks}次移动添加新方块)`;
  }

  function addRandomPairEndless(){
    // 找出所有空位
    const emptySpots = [];
    for(let y=0; y<SIZE; y++){
      for(let x=0; x<SIZE; x++){
        if(board[y][x] === 0) emptySpots.push({x, y});
      }
    }
    
    if(emptySpots.length < 2){
      // 游戏结束
      endlessGameOver = true;
      showMsg('endless', `游戏结束！共完成 ${endlessMoves} 次移动！`);
      return false;
    }
    
    let newType;
    
    // 策略：优先使用递增编号，但当编号>12时，检查1-12是否有空闲的可以重用
    if(endlessNextType <= 12){
      // 编号还在1-12范围内，直接使用
      newType = endlessNextType;
      endlessNextType++;
    } else {
      // 编号超过12，检查1-12中是否有未使用的
      const usedTypes = new Set();
      for(let y=0; y<SIZE; y++){
        for(let x=0; x<SIZE; x++){
          if(board[y][x] > 0) usedTypes.add(board[y][x]);
        }
      }
      
      // 找到1-12中最小的未使用编号
      let foundReuse = false;
      for(let i=1; i<=12; i++){
        if(!usedTypes.has(i)){
          newType = i;
          foundReuse = true;
          break;
        }
      }
      
      // 如果1-12都在使用，继续递增
      if(!foundReuse){
        newType = endlessNextType;
        endlessNextType++;
      }
    }
    
    // 随机放置两个位置
    const idx1 = Math.floor(Math.random() * emptySpots.length);
    const spot1 = emptySpots.splice(idx1, 1)[0];
    const idx2 = Math.floor(Math.random() * emptySpots.length);
    const spot2 = emptySpots[idx2];
    
    board[spot1.y][spot1.x] = newType;
    board[spot2.y][spot2.x] = newType;
    
    showMsg('endless', `添加了方块 ${newType}！`);
    return true;
  }

  document.getElementById('endlessStartBtn').onclick = startEndless;
  document.getElementById('endlessRestartBtn').onclick = () => {
    document.getElementById('endlessStartBtn').style.display = 'inline-block';
    document.getElementById('endlessRestartBtn').style.display = 'none';
    showMsg('endless', '点击"开始游戏"开始无尽挑战！');
  };

  // ========== 编辑器 ==========
  function initEditor(){
    board = Array.from({length:SIZE}, ()=> Array(SIZE).fill(0));
    selected = null;
    editorMode = 'place';
    nextBlockNumber = 1;
    placingBlock = null;
    updateEditorButtons();
    updateNextBlockPreview();
    updateCapacityInfo();
    renderBoard('editor');
    showMsg('editor', '点击"放置方块"，然后在棋盘上点击两次放置一对方块');
  }

  function updateCapacityInfo(){
    const totalCells = SIZE * SIZE;
    const usedCells = countBlocks();
    const maxPairs = Math.floor((totalCells - 1) / 2); // 至少留一个空格
    const currentPairs = usedCells / 2;
    
    const capacityText = document.getElementById('capacityInfo');
    if(capacityText){
      capacityText.textContent = `容量：${currentPairs}/${maxPairs} 对 (${usedCells}/${totalCells-1} 格)`;
      if(currentPairs >= maxPairs){
        capacityText.style.color = '#e74';
      } else {
        capacityText.style.color = '#666';
      }
    }
  }

  function canPlaceMoreBlocks(){
    const totalCells = SIZE * SIZE;
    const usedCells = countBlocks();
    // 至少需要留1个空格，所以最多用24个格子（12对方块）
    return usedCells < (totalCells - 1);
  }

  function updateEditorButtons(){
    const placeBtn = document.getElementById('placeBtn');
    const deleteBtn = document.getElementById('deleteBtn');
    
    // 移除所有active class
    placeBtn.classList.remove('active');
    deleteBtn.classList.remove('active');
    
    // 根据当前模式添加active class
    if(editorMode === 'place'){
      placeBtn.classList.add('active');
    } else {
      deleteBtn.classList.add('active');
    }
    
    // 检查容量，如果满了禁用放置按钮
    if(!canPlaceMoreBlocks()){
      placeBtn.disabled = true;
      placeBtn.style.opacity = '0.5';
      placeBtn.style.cursor = 'not-allowed';
    } else {
      placeBtn.disabled = false;
      placeBtn.style.opacity = '1';
      placeBtn.style.cursor = 'pointer';
    }
  }

  function updateNextBlockPreview(){
    const preview = document.getElementById('nextBlockPreview');
    const text = document.getElementById('nextBlockText');
    
    if(nextBlockNumber > 12){
      preview.style.background = '#999';
      preview.textContent = nextBlockNumber;
      text.textContent = `方块 ${nextBlockNumber}`;
    } else {
      preview.className = 'block-' + nextBlockNumber;
      preview.textContent = nextBlockNumber;
      text.textContent = `方块 ${nextBlockNumber}`;
    }
  }

  function getNextBlockNumber(){
    // 找出当前最大的方块编号
    let maxNum = 0;
    for(let y=0; y<SIZE; y++){
      for(let x=0; x<SIZE; x++){
        if(board[y][x] > maxNum) maxNum = board[y][x];
      }
    }
    return maxNum + 1;
  }

  document.getElementById('placeBtn').onclick = () => {
    if(!canPlaceMoreBlocks()){
      showMsg('editor', '棋盘已满！最多可放置12对方块（需保留至少1个空格）');
      return;
    }
    editorMode = 'place';
    placingBlock = null;
    updateEditorButtons();
    showMsg('editor', '放置模式：在棋盘上点击两次放置一对方块');
  };

  document.getElementById('deleteBtn').onclick = () => {
    editorMode = 'delete';
    placingBlock = null;
    updateEditorButtons();
    showMsg('editor', '删除模式：点击方块进行删除');
  };

  document.getElementById('clearBtn').onclick = () => {
    if(countBlocks() > 0 && !confirm('确定要清空整个棋盘吗？')) return;
    board = Array.from({length:SIZE}, ()=> Array(SIZE).fill(0));
    editorMode = 'place';
    placingBlock = null;
    nextBlockNumber = 1;
    updateEditorButtons();
    updateNextBlockPreview();
    updateCapacityInfo();
    renderBoard('editor');
    showMsg('editor', '棋盘已清空');
  };

  document.getElementById('testBtn').onclick = () => {
    // 检查是否所有方块都成对
    const typeCounts = {};
    for(let y=0; y<SIZE; y++){
      for(let x=0; x<SIZE; x++){
        const v = board[y][x];
        if(v > 0){
          typeCounts[v] = (typeCounts[v] || 0) + 1;
        }
      }
    }
    
    for(let type in typeCounts){
      if(typeCounts[type] !== 2){
        showMsg('editor', `错误：方块${type}只有${typeCounts[type]}个，必须是2个！`);
        return;
      }
    }
    
    if(countBlocks() === 0){
      showMsg('editor', '棋盘为空，无法测试');
      return;
    }
    
    currentMode = 'editorTest';
    selected = null;
    document.getElementById('placeBtn').style.display = 'none';
    document.getElementById('deleteBtn').style.display = 'none';
    document.getElementById('testBtn').style.display = 'none';
    document.getElementById('saveBtn').style.display = 'none';
    document.getElementById('nextBlockPreview').parentElement.style.display = 'none';
    document.getElementById('backToEditBtn').style.display = 'inline-block';
    
    // 修复：在测试模式下隐藏清空按钮
    document.getElementById('clearBtn').style.display = 'none';
    
    renderBoard('editor');
    showMsg('editor', '测试模式：点击方块，用方向键移动');
  };

  // 修复：返回编辑按钮功能
  document.getElementById('backToEditBtn').onclick = () => {
    // 重新显示编辑器按钮
    document.getElementById('placeBtn').style.display = 'inline-block';
    document.getElementById('deleteBtn').style.display = 'inline-block';
    document.getElementById('testBtn').style.display = 'inline-block';
    document.getElementById('saveBtn').style.display = 'inline-block';
    document.getElementById('nextBlockPreview').parentElement.style.display = 'block';
    document.getElementById('backToEditBtn').style.display = 'none';
    document.getElementById('clearBtn').style.display = 'inline-block';
    
    // 重置模式
    currentMode = 'editor';
    
    // 重新初始化编辑器状态
    updateEditorButtons();
    updateNextBlockPreview();
    updateCapacityInfo();
    
    // 重新渲染棋盘
    renderBoard('editor');
    showMsg('editor', '返回编辑模式');
  };

  document.getElementById('saveBtn').onclick = () => {
    // 检查是否所有方块都成对
    const typeCounts = {};
    for(let y=0; y<SIZE; y++){
      for(let x=0; x<SIZE; x++){
        const v = board[y][x];
        if(v > 0){
          typeCounts[v] = (typeCounts[v] || 0) + 1;
        }
      }
    }
    
    for(let type in typeCounts){
      if(typeCounts[type] !== 2){
        showMsg('editor', `错误：方块${type}只有${typeCounts[type]}个！`);
        return;
      }
    }
    
    if(countBlocks() === 0){
      showMsg('editor', '棋盘为空');
      return;
    }
    document.getElementById('saveArea').style.display = 'block';
    document.getElementById('levelName').focus();
  };

  window.saveLevelWithName = function(){
    const name = document.getElementById('levelName').value.trim();
    if(!name){
      showMsg('editor', '请输入关卡名称');
      return;
    }
    
    const levels = JSON.parse(localStorage.getItem('customLevels') || '[]');
    levels.push({
      id: Date.now(),
      name: name,
      board: JSON.stringify(board),
      createdAt: new Date().toLocaleString('zh-CN')
    });
    localStorage.setItem('customLevels', JSON.stringify(levels));
    
    document.getElementById('saveArea').style.display = 'none';
    document.getElementById('levelName').value = '';
    showMsg('editor', `关卡"${name}"已保存！`);
  };

  window.cancelSave = function(){
    document.getElementById('saveArea').style.display = 'none';
    document.getElementById('levelName').value = '';
  };

  // ========== 载入关卡 ==========
  function loadSavedLevels(){
    const levels = JSON.parse(localStorage.getItem('customLevels') || '[]');
    const listEl = document.getElementById('levelList');
    
    if(levels.length === 0){
      listEl.innerHTML = '<div style="text-align:center; color:#999; padding:40px;">暂无保存的关卡<br><small>在关卡编辑器中创建并保存关卡</small></div>';
      return;
    }
    
    listEl.innerHTML = '<h3 style="margin:0 0 12px 0; font-size:16px;">已保存的关卡</h3>';
    levels.forEach(level => {
      const item = document.createElement('div');
      item.className = 'level-item';
      item.innerHTML = `
        <div>
          <div style="font-weight:600;">${level.name}</div>
          <div style="font-size:11px; color:#999; margin-top:2px;">${level.createdAt}</div>
        </div>
        <div>
          <button class="secondary load-btn" data-id="${level.id}">载入</button>
          <button class="danger delete-btn" data-id="${level.id}">删除</button>
        </div>
      `;
      
      // 添加事件监听器
      const loadBtn = item.querySelector('.load-btn');
      const deleteBtn = item.querySelector('.delete-btn');
      
      loadBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        loadCustomLevel(level.id);
      });
      
      deleteBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        deleteLevel(level.id);
      });
      
      listEl.appendChild(item);
    });
  }

  function loadCustomLevel(id){
    const levels = JSON.parse(localStorage.getItem('customLevels') || '[]');
    const level = levels.find(l => l.id === id);
    if(level){
      board = JSON.parse(level.board);
      selected = null;
      switchView('play', true);
      currentMode = 'play';
      renderBoard('play');
      showMsg('play', `已载入关卡：${level.name}`);
    }
  }

  function deleteLevel(id){
    if(!confirm('确定删除这个关卡？')) return;
    let levels = JSON.parse(localStorage.getItem('customLevels') || '[]');
    levels = levels.filter(l => l.id !== id);
    localStorage.setItem('customLevels', JSON.stringify(levels));
    loadSavedLevels();
  }

  // ========== 通用渲染 ==========
  function renderBoard(mode){
    const boardEl = document.getElementById(mode + 'Board');
    boardEl.innerHTML = '';
    
    for(let y=0; y<SIZE; y++){
      for(let x=0; x<SIZE; x++){
        const v = board[y][x];
        const cell = document.createElement('div');
        cell.className = 'cell';
        if(v===0) cell.classList.add('empty');
        else cell.classList.add('block-'+v);
        cell.textContent = v===0 ? '' : String(v);
        
        if(selected && selected.x===x && selected.y===y && currentMode !== 'editor'){
          cell.classList.add('selected');
        }
        
        cell.onclick = () => handleCellClick(x, y, mode);
        boardEl.appendChild(cell);
      }
    }
    blocksRemaining = countBlocks();
  }

  function handleCellClick(x, y, mode){
    if(currentMode === 'editor'){
      if(editorMode === 'delete'){
        // 删除模式
        if(board[y][x] !== 0){
          const deletedType = board[y][x];
          // 删除这对方块
          for(let dy=0; dy<SIZE; dy++){
            for(let dx=0; dx<SIZE; dx++){
              if(board[dy][dx] === deletedType){
                board[dy][dx] = 0;
              }
            }
          }
          showMsg('editor', `已删除方块 ${deletedType}`);
          nextBlockNumber = getNextBlockNumber();
          updateNextBlockPreview();
          updateCapacityInfo();
          updateEditorButtons();
          renderBoard('editor');
        }
      } else {
        // 放置模式
        if(board[y][x] !== 0){
          showMsg('editor', '该位置已有方块');
          return;
        }
        
        if(!canPlaceMoreBlocks() && !placingBlock){
          showMsg('editor', '棋盘已满！最多12对方块');
          return;
        }
        
        if(!placingBlock){
          // 放置第一个
          placingBlock = {
            type: nextBlockNumber,
            firstPos: {x, y}
          };
          board[y][x] = nextBlockNumber;
          showMsg('editor', `放置了第1个方块 ${nextBlockNumber}，再点击一个空位放置第2个`);
          renderBoard('editor');
        } else {
          // 放置第二个
          board[y][x] = placingBlock.type;
          showMsg('editor', `完成方块 ${placingBlock.type} 的配对`);
          nextBlockNumber++;
          updateNextBlockPreview();
          updateCapacityInfo();
          updateEditorButtons();
          placingBlock = null;
          renderBoard('editor');
        }
      }
    } else {
      // 游戏模式/测试模式/无尽模式
      const v = board[y][x];
      if(v===0){ 
        selected=null;
        renderBoard(mode);
        return;
      }
      selected={x,y};
      renderBoard(mode);
      showMsg(mode, `选中方块 ${v}`);
    }
  }

  function showMsg(mode, text){
    document.getElementById(mode + 'Msg').textContent = text;
  }

  function countBlocks(){
    let c=0;
    for(let y=0;y<SIZE;y++) for(let x=0;x<SIZE;x++) if(board[y][x]>0) c++;
    return c;
  }

  // ========== 游戏逻辑 ==========
  function findOtherOfType(type, excludeX, excludeY){
    for(let y=0;y<SIZE;y++){
      for(let x=0;x<SIZE;x++){
        if(board[y][x]===type && !(x===excludeX && y===excludeY)) return {x,y};
      }
    }
    return null;
  }

  function movePiece(fromX,fromY,toX,toY){
    board[toY][toX] = board[fromY][fromX];
    board[fromY][fromX] = 0;
  }

  function slideSelected(dirKey){
    if(!selected) return;
    if(currentMode !== 'play' && currentMode !== 'editorTest' && currentMode !== 'endless') return;
    if(currentMode === 'endless' && endlessGameOver) return;
    
    const dir = DIRS[dirKey];
    if(!dir) return;
    
    const renderMode = currentMode === 'editorTest' ? 'editor' : currentMode;
    const sx = selected.x, sy = selected.y;
    const sType = board[sy][sx];

    const nx = sx + dir.x, ny = sy + dir.y;
    if(!inside(nx,ny)){ showMsg(renderMode, '不能滑出边界'); return; }
    if(board[ny][nx]===0){ showMsg(renderMode, '不能向空格滑动'); return; }

    const neighborType = board[ny][nx];

    if(neighborType === sType){
      board[sy][sx] = 0;
      board[ny][nx] = 0;
      selected = null;
      
      if(currentMode === 'endless'){
        endlessMoves++;
        movesUntilNewBlocks--;
        updateEndlessScore();
        
        // 每3次移动添加一对新方块
        if(movesUntilNewBlocks <= 0){
          if(!addRandomPairEndless()){
            renderBoard(renderMode);
            return;
          }
          movesUntilNewBlocks = 3; // 重置计数器
        }
      }
      
      renderBoard(renderMode);
      showMsg(renderMode, `方块 ${sType} 消除`);
      if(countBlocks() === 0 && currentMode !== 'endless'){
        showMsg(renderMode, '恭喜通关！');
      }
      return;
    }

    const movingBlockSet = new Set([`${sx},${sy}`]);
    const result = resolveTeleportChain(sx, sy, sType, nx, ny, dir, 0, movingBlockSet, sx, sy, null);
    
    if(!result.success){
      showMsg(renderMode, result.message);
      return;
    }

    if(result.eliminated){
      selected = null;
      
      if(currentMode === 'endless'){
        endlessMoves++;
        movesUntilNewBlocks--;
        updateEndlessScore();
        
        // 每3次移动添加一对新方块
        if(movesUntilNewBlocks <= 0){
          if(!addRandomPairEndless()){
            renderBoard(renderMode);
            return;
          }
          movesUntilNewBlocks = 3; // 重置计数器
        }
      }
      
      renderBoard(renderMode);
      showMsg(renderMode, `方块 ${sType} 传送消除`);
      if(countBlocks() === 0 && currentMode !== 'endless'){
        showMsg(renderMode, '恭喜通关！');
      }
      return;
    }

    if(result.swap){
      const {swapPortalX, swapPortalY, swapPortalType, finalX, finalY} = result;
      board[sy][sx] = 0;
      board[swapPortalY][swapPortalX] = 0;
      board[finalY][finalX] = sType;
      board[sy][sx] = swapPortalType;
      selected = {x:finalX, y:finalY};
      
      if(currentMode === 'endless'){
        endlessMoves++;
        movesUntilNewBlocks--;
        updateEndlessScore();
        
        // 每3次移动添加一对新方块
        if(movesUntilNewBlocks <= 0){
          if(!addRandomPairEndless()){
            renderBoard(renderMode);
            showMsg(renderMode, `对调成功！游戏结束`);
            return;
          }
          movesUntilNewBlocks = 3; // 重置计数器
        }
      }
      
      renderBoard(renderMode);
      showMsg(renderMode, `对调完成`);
      return;
    }

    const {finalX, finalY} = result;
    board[sy][sx] = 0;
    board[finalY][finalX] = sType;
    selected = {x:finalX, y:finalY};
    
    if(currentMode === 'endless'){
      endlessMoves++;
      movesUntilNewBlocks--;
      updateEndlessScore();
      
      // 每3次移动添加一对新方块
      if(movesUntilNewBlocks <= 0){
        if(!addRandomPairEndless()){
          renderBoard(renderMode);
          showMsg(renderMode, `移动成功！游戏结束`);
          return;
        }
        movesUntilNewBlocks = 3; // 重置计数器
      }
    }
    
    renderBoard(renderMode);
    showMsg(renderMode, `已移动`);
  }

  function resolveTeleportChain(movingX, movingY, movingType, startX, startY, dir, depth, movingBlockSet, originX, originY, potentialSwapPortal){
    if(depth > 50) return {success:false, message:'递归超限'};

    let encounteredType = board[startY][startX];
    let currentX = startX, currentY = startY;
    let stepGuard = 0;
    const visited = new Set();

    while(stepGuard++ < 100){
      const posKey = `${currentX},${currentY}`;
      if(visited.has(posKey)) return {success:false, message:'检测到循环'};
      visited.add(posKey);

      const portal = findOtherOfType(encounteredType, currentX, currentY);
      if(!portal) return {success:false, message:`找不到配对`};

      if(portal.x === originX && portal.y === originY && potentialSwapPortal){
        return {
          success: true, swap: true,
          swapPortalX: potentialSwapPortal.x,
          swapPortalY: potentialSwapPortal.y,
          swapPortalType: potentialSwapPortal.type,
          finalX: potentialSwapPortal.x,
          finalY: potentialSwapPortal.y
        };
      }

      let landX = portal.x + dir.x;
      let landY = portal.y + dir.y;

      if(!inside(landX, landY)){
        const oppX = portal.x - dir.x;
        const oppY = portal.y - dir.y;
        if(!inside(oppX, oppY)) return {success:false, message:'边界阻挡'};

        const oppVal = board[oppY][oppX];
        if(oppVal === 0){
          movePiece(portal.x, portal.y, oppX, oppY);
          landX = portal.x; landY = portal.y;
        } else if(oppVal === encounteredType){
          board[portal.y][portal.x] = 0;
          board[oppY][oppX] = 0;
          landX = portal.x; landY = portal.y;
        } else {
          const portalType = board[portal.y][portal.x];
          const reverseDir = {x: -dir.x, y: -dir.y};
          const portalTargetX = portal.x + reverseDir.x;
          const portalTargetY = portal.y + reverseDir.y;
          
          if(!inside(portalTargetX, portalTargetY)) return {success:false, message:'传送门无法腾空间'};
          const portalTargetVal = board[portalTargetY][portalTargetX];
          if(portalTargetVal === 0) return {success:false, message:'反方向是空格'};
          
          const portalKey = `${portal.x},${portal.y}`;
          if(movingBlockSet.has(portalKey)) return {success:false, message:'检测到死锁'};
          
          if(portalTargetVal === portalType){
            board[portal.y][portal.x] = 0;
            board[portalTargetY][portalTargetX] = 0;
            landX = portal.x; landY = portal.y;
          } else {
            const newMovingBlockSet = new Set(movingBlockSet);
            newMovingBlockSet.add(portalKey);
            const swapInfo = {x: portal.x, y: portal.y, type: portalType};
            
            const portalMoveResult = resolveTeleportChain(
              portal.x, portal.y, portalType,
              portalTargetX, portalTargetY,
              reverseDir, depth + 1, newMovingBlockSet,
              originX, originY, swapInfo
            );
            
            if(!portalMoveResult.success) return portalMoveResult;
            if(portalMoveResult.swap) return portalMoveResult;
            
            if(portalMoveResult.eliminated){
              landX = portal.x; landY = portal.y;
            } else {
              board[portal.y][portal.x] = 0;
              board[portalMoveResult.finalY][portalMoveResult.finalX] = portalType;
              landX = portal.x; landY = portal.y;
            }
          }
        }
      }

      if(inside(landX, landY)){
        const landingVal = board[landY][landX];
        if(landingVal === 0) return {success:true, finalX: landX, finalY: landY};
        
        if(landingVal === movingType){
          if(landX === movingX && landY === movingY) return {success:false, message:'回到起点'};
          board[landY][landX] = 0;
          board[movingY][movingX] = 0;
          return {success:true, eliminated:true};
        }
        
        encounteredType = landingVal;
        currentX = landX; currentY = landY;
      }
    }
    return {success:false, message:'超出最大链长度'};
  }

  window.addEventListener('keydown', (e)=>{
    if(DIRS[e.key]){
      e.preventDefault();
      slideSelected(e.key);
    }
  });

  // 初始化
  resetRandom();
</script>
</body>
</html>